#pragma once
#include "StdAfx.h"
#include "EntityControl.h"

#include "ControlLogic.h"
#include "Controller.h"





//const std::string EntityControl::POSITION_PARAMETER="position";
//const std::string EntityControl::HITPOINT_PARAMETER="hitpoint";
//const std::string EntityControl::KILLED_PARAMETER="killed";
//const std::string EntityControl::SPEED_PARAMETER="speed";
//const std::string EntityControl::LOOKAT_PARAMETER="lookat";
//const std::string EntityControl::MAP_WAYPOINT_PARAMETER="map_waypoint";
//const std::string EntityControl::SCORE_PARAMETER="score";

EntityControl::EntityControl(int hp)
	:Ogre::ManualObject("")
{
	HitPoint = hp;
	setupParameters();
	entityState = PLAYING;
}

EntityControl::EntityControl(const Ogre::String entityName, int hp)
	:Ogre::ManualObject(entityName)
{
	HitPoint = hp;
	//TriggerList = new std::vector<Trigger*>;

	setupParameters();
	entityState = PLAYING;
}

void EntityControl::setupParameters()
{
	actorInited = false;

	parameterMap[POSITION_PARAMETER] = new VectorEntityParameter(POSITION_PARAMETER);
	listenerMap[POSITION_PARAMETER] = new std::vector<IParameterChangedListener*>();

	parameterMap[HITPOINT_PARAMETER] = new IntEntityParameter(HITPOINT_PARAMETER);
	parameterMap[HITPOINT_PARAMETER]->setValue((void*)&HitPoint);
	listenerMap[HITPOINT_PARAMETER] = new std::vector<IParameterChangedListener*>();

	parameterMap[KILLED_PARAMETER] = new CustomEntityParameter<bool>(KILLED_PARAMETER);
	parameterMap[KILLED_PARAMETER]->setValue((void*)false);
	listenerMap[KILLED_PARAMETER] = new std::vector<IParameterChangedListener*>();

	parameterMap[SPEED_PARAMETER] = new IntEntityParameter(SPEED_PARAMETER);
	listenerMap[SPEED_PARAMETER] = new std::vector<IParameterChangedListener*>();
	
	IntEntityParameter newParam = IntEntityParameter(SPEED_PARAMETER);
	newParam.setIntValue(100);
	setParameter(SPEED_PARAMETER, &newParam);

	parameterMap[LOOKAT_PARAMETER] = new VectorEntityParameter(LOOKAT_PARAMETER);
	listenerMap[LOOKAT_PARAMETER] = new std::vector<IParameterChangedListener*>();

	parameterMap[MAP_WAYPOINT_PARAMETER] = new IntEntityParameter(MAP_WAYPOINT_PARAMETER);
	((IntEntityParameter*)parameterMap[MAP_WAYPOINT_PARAMETER])->setIntValue(0);
	listenerMap[MAP_WAYPOINT_PARAMETER] = new std::vector<IParameterChangedListener*>();

	parameterMap[SCORE_PARAMETER] = new IntEntityParameter(SCORE_PARAMETER);
	((IntEntityParameter*)parameterMap[SCORE_PARAMETER])->setIntValue(0);
	listenerMap[SCORE_PARAMETER] = new std::vector<IParameterChangedListener*>();
}

EntityControl::~EntityControl(void)
{
	//The delete of the PhysicsEntity* bulletActor and Ogre::Entity* modelEntity is in the game.cpp
	//because the SceneManager for Ogre and PhysX needed for these operations.
	

	detachFromParent();

	Ogre::ManualObject::clear();

	/*if(controller)
	{
		delete controller;
	}*/

	/*std::vector<EntityBody*>::iterator iterator = bodies.begin();

	while(iterator != bodies.end())
	{
		EntityBody * body = *iterator;
		delete body;
		iterator = bodies.erase(iterator);
		
	}*/
	


	/*std::vector<Trigger*>::iterator i = TriggerList.begin();
	while(i != TriggerList.end())
	{
		delete *i;
		i++;
	}*/

}

void* EntityControl::operator new (size_t size)
{
	return  StackAllocatorManager::getSingleton().allocateObject<EntityControl>("EntityControl",1000);
}


void EntityControl::operator delete (void *currentEntity)
{
	StackAllocatorManager::getSingleton().freeObject<EntityControl>("EntityControl",((EntityControl*)currentEntity));
}

void EntityControl::deleteBodies()
{

	std::vector<EntityBody*>::iterator iterator = bodies.begin();

	while(iterator != bodies.end())
	{
		EntityBody * body = *iterator;
		delete body;
		iterator = bodies.erase(iterator);
		

	}


}




//bool EntityControl::isActorInited()
//{
//	return actorInited;
//}

void EntityControl::addController(ControlLogic* logic)
{
	controllers.push_back(logic->makeController());
}

bool EntityControl::control(Controller *controller,const ControlContext& context)
{

	if(masterBody->getLastPosition()!=masterBody->getPosition())
	{
		setPosition(masterBody->getPosition());
	}

	if(masterBody->getLastOrientation()!= masterBody->getOrientation())
	{
		setOrientation(masterBody->getOrientation());
	}
	bool nextController = false;

	if(controller)
		  nextController = controller->apply(this, context);

	std::vector<Trigger*>::iterator i = dirtyTriggers.begin();
	while( i!=dirtyTriggers.end())
	{
		
		bool res = (*i)->UseTrigger(this);
		if(res)
		{
			(*i)->setDeletedFlag(this);
		}
		 i++;
	}

	dirtyTriggers.clear();
	dirtyTriggers.swap(newDirtyTriggers);


	int r = rand()%1000;

	if(r<=10 )
	{
		std::vector<Trigger*>::iterator i = TriggerList.begin();
		while( i!=TriggerList.end())
		{
			if((*i)->getDeletedFlag())
			{
				i = TriggerList.erase(i);
			}
			else
			{
				i++;
			}
		}
	}

	return nextController;
}

// render
// animate

//PhysicsEntity* EntityControl::getPhysicsActor()
//{
//	return bulletActor;
//}
//
//void EntityControl::setPhysicsActor(PhysicsEntity* pe)
//{
//	bulletActor = pe;
//	setPosition(modelEntity->getParentNode()->getPosition());
//	//setLookAt(Ogre::Vector3::ZERO);
//
//	actorInited = true;
//}
//
//Ogre::Entity* EntityControl::getModelActor()
//{
//	return modelEntity;
//}
//
//void EntityControl::setModelActor(Ogre::Entity* entity)
//{
//	modelEntity = entity;
//	
//}

void EntityControl::setMasterBody(EntityBody * body)
{
	masterBody = body;
}

EntityBody *  EntityControl::getMasterBody()
{
	return masterBody;
}

void EntityControl::addBody(EntityBody * body)
{
	bodies.push_back(body);
}

void EntityControl::removeBody(EntityBody * body)
{
	std::vector<EntityBody*>::iterator iterator = bodies.begin();

	while(iterator != bodies.end())
	{
		if((*iterator)== body)
		{
			iterator = bodies.erase(iterator);
			break;
		}
		iterator++;
	
	}
}

std::vector<EntityBody*>* EntityControl::getBodies()
{
	return (&bodies);
}


void EntityControl::causeDamage(float dmg)
{
	HitPoint-=dmg;
	
	IntEntityParameter newParam = IntEntityParameter(HITPOINT_PARAMETER);
	newParam.setIntValue(HitPoint);
	setParameter(HITPOINT_PARAMETER, &newParam);

	if(HitPoint<=0)
	{
		killEntity();
	}
}

void EntityControl::AddTrigger(Trigger *trigger)
{
	TriggerList.push_back(trigger);
	trigger->subscribeParameterChanged(this);
	dirtyTriggers.push_back(trigger);
}

std::vector<Controller*> * EntityControl::getControllers()
{
 return &controllers;
}

Ogre::Vector3 EntityControl::getPosition()
{
	//return bulletActor->getCenterOfMassPosition();
	return masterBody->getPosition();
}

void  EntityControl::clear(void)
{
	//Ogre::ManualObject::clear();


	//delete controller;

	/*std::vector<Trigger*>::iterator i = TriggerList.begin();
	while(i != TriggerList.end())
	{
		delete *i;
		i++;
	}*/

}


void EntityControl::setTriggerDirty(Trigger *trigger)
{
	newDirtyTriggers.push_back(trigger);

}

void EntityControl::setParameter(std::string name,EntityParameter *param)
{
	/*if(param->getType()==IntEntityParameter::TYPE_NAME)
	{
		parameterMap[name].
	}*/

	if(listenerMap.find(name)==listenerMap.end())
	{
		listenerMap[name] = new std::vector<IParameterChangedListener*>(); 
	}

	std::vector<IParameterChangedListener*>::iterator i = listenerMap[name]->begin();

	while(i != listenerMap[name]->end())
	{
		(*i)->parameterChanged(this,name,parameterMap[name],param);
		i++;
	}

	if(isParameterFilled(name))
	{
		parameterMap[name]->setValue(param->getValue());
	}
	else
	{
		parameterMap[name] = param;
	}
	
	


}

EntityParameter* EntityControl::getParameter(std::string name)
{
	return parameterMap[name];

}

void EntityControl::subscribeForParameter(std::string name,IParameterChangedListener *listener)
{
	listenerMap[name]->push_back(listener);

}

void EntityControl::unSubscribeForParameter(std::string name,IParameterChangedListener *listener)
{
	
	
	std::vector<IParameterChangedListener*>::iterator i = listenerMap[name]->begin();

	while(i != listenerMap[name]->end())
	{
		if(*i == listener)
		{

			i = listenerMap[name]->erase(i);
			break;
		}
		i++;
	}

	
}


bool EntityControl::isParameterFilled(std::string name)
{
	std::map<std::string, EntityParameter*>::iterator it = parameterMap.find(name);
	
	return it!= parameterMap.end();
}


void EntityControl::setPosition(Ogre::Vector3 pos)
{
	/*NxActor* actor = this->getPhysicsActor()->getNxActor();
	Ogre::SceneNode* ogreNode = this->getPhysicsActor()->getOgreNode();

	ogreNode->setPosition(pos);

	pos = ogreNode->_getDerivedPosition();
	actor->moveGlobalPosition(NxVec3(pos.x,pos.y,pos.z));*/

	masterBody->setPosition(pos);

	for(int i=0; i<bodies.size(); i++)
	{
		bodies[i]->setPosition(pos);
	}
	

	VectorEntityParameter newParam = VectorEntityParameter(POSITION_PARAMETER);
	newParam.setVectorValue(pos);
	
	setParameter(POSITION_PARAMETER, &newParam);
}

void  EntityControl::killEntity()
{
	/*for(int i=0; i<controllers.size();i++)
	{
		controllers[i]->kill();
	}*/
	
	this->kill();
	

	CustomEntityParameter<bool> newParam = CustomEntityParameter<bool>(KILLED_PARAMETER);
	newParam.setCustomValue((void*)true);
	setParameter(KILLED_PARAMETER, &newParam);

	for(int i=0; i<bodies.size(); i++)
	{
		bodies[i]->killBody();
	}

}

void EntityControl::setLookAt(Ogre::Vector3 pos)
{
	/*NxActor* actor = this->getPhysicsActor()->getNxActor();
	Ogre::SceneNode* ogreNode = this->getPhysicsActor()->getOgreNode();

	ogreNode->lookAt(pos,Ogre::Node::TransformSpace::TS_WORLD);

	Ogre::Quaternion orient = ogreNode->_getDerivedOrientation();
	actor->moveGlobalOrientation(NxQuat(NxVec3(orient.x,orient.y,orient.z),orient.w));*/

	masterBody->setLookAt(pos);

	for(int i=0; i<bodies.size(); i++)
	{
		bodies[i]->setLookAt(pos);
	}

	parameterMap[LOOKAT_PARAMETER]->setValue((void*)&pos);


}

void EntityControl::setOrientation(Ogre::Quaternion ori)
{
	masterBody->setOrientation(ori);

	for(int i=0; i<bodies.size(); i++)
	{
		bodies[i]->setOrientation(ori);
	}

}

Ogre::Quaternion EntityControl::getOrientation()
{

	return masterBody->getOrientation();
}



void EntityControl::setLocalOrientation(Ogre::Quaternion ori)
{
	masterBody->setLocalOrientation(ori);

	for(int i=0; i<bodies.size(); i++)
	{
		bodies[i]->setLocalOrientation(ori);
	}

}

Ogre::Quaternion EntityControl::getLocalOrientation()
{

	return masterBody->getLocalOrientation();
}

void EntityControl::addForce(Ogre::Vector3 force)
{
	masterBody->addForce(force);

	for(int i=0; i<bodies.size(); i++)
	{
		bodies[i]->addForce(force);
	}
}

void EntityControl::addTorque(Ogre::Vector3 torque)
{
	masterBody->addTorque(torque);

	for(int i=0; i<bodies.size(); i++)
	{
		bodies[i]->addTorque(torque);
	}

}

void EntityControl::setLocalPosition(Ogre::Vector3 pos)
{
	masterBody->setLocalPosition(pos);

	for(int i=0; i<bodies.size(); i++)
	{
		bodies[i]->setLocalPosition(pos);
	}
}

Ogre::Vector3 EntityControl::getLocalPosition()
{
	return masterBody->getLocalPosition();
}




std::map<std::string, std::vector<IParameterChangedListener*>*> EntityControl::getListenerMap()
{

	return listenerMap;

}

std::vector<Trigger*> EntityControl::getTriggerList()
{
	return TriggerList;

}


std::vector<Trigger*> EntityControl::getDirtyTriggerList()
{
	return dirtyTriggers;

}

std::vector<Trigger*> EntityControl::getNewDirtyTriggerList()
{
	return newDirtyTriggers;

}

void  EntityControl::setEntityState(EntityState state)
{
	
	entityState = state;
}

void EntityControl::kill(){
	entityState = DEAD;
}


bool EntityControl::isKilled(){
	return (entityState==DEAD);
}

void EntityControl::GameOverMan(){
	entityState = GAMEOVER;
}


bool EntityControl::isGameOver(){
	return (entityState==GAMEOVER);
}

bool EntityControl::isReadyToDie()
{

	return (entityState==REMOVED);
}
void EntityControl::DDDIIIE()
{
	entityState=REMOVED;
}

void EntityControl::wait(){
	entityState = WAITING;
}


bool EntityControl::isWaiting(){
	return (entityState==WAITING);
}


void EntityControl::play(){
	entityState = PLAYING;
}


bool EntityControl::isPlaying(){
	return (entityState==PLAYING);
}
